package com.kexio.file.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kexio.file.entity.FileStorageConfig;
import com.kexio.file.mapper.FileStorageConfigMapper;
import com.kexio.file.service.FileStorageConfigService;

/**
 * 文件存储配置服务实现
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Service
public class FileStorageConfigServiceImpl extends ServiceImpl<FileStorageConfigMapper, FileStorageConfig> 
        implements FileStorageConfigService {

    private static final Logger log = LoggerFactory.getLogger(FileStorageConfigServiceImpl.class);

    @Autowired
    private FileStorageConfigMapper fileStorageConfigMapper;
    
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public IPage<FileStorageConfig> pageConfigs(Long current, Long size, String configName, String configType, Boolean enabled) {
        Page<FileStorageConfig> page = new Page<>(current, size);
        LambdaQueryWrapper<FileStorageConfig> wrapper = new LambdaQueryWrapper<>();
        
        if (StringUtils.hasText(configName)) {
            wrapper.like(FileStorageConfig::getConfigName, configName);
        }
        if (StringUtils.hasText(configType)) {
            wrapper.eq(FileStorageConfig::getConfigType, configType);
        }
        if (enabled != null) {
            wrapper.eq(FileStorageConfig::getIsEnabled, enabled);
        }
        
        // 按创建时间倒序
        wrapper.orderByDesc(FileStorageConfig::getCreateTime);
        
        return this.page(page, wrapper);
    }

    @Override
    public List<FileStorageConfig> listEnabledConfigs() {
        // 租户ID由MyBatis-Plus租户拦截器自动处理
        return fileStorageConfigMapper.selectEnabledByTenantId();
    }

    @Override
    public List<FileStorageConfig> listConfigsByType(String configType) {
        // 租户ID由MyBatis-Plus租户拦截器自动处理
        return fileStorageConfigMapper.selectByTenantIdAndType(configType);
    }

    @Override
    public FileStorageConfig getDefaultConfig() {
        // 租户ID由MyBatis-Plus租户拦截器自动处理
        return fileStorageConfigMapper.selectDefaultByTenantId();
    }

    @Override
    @Transactional
    public FileStorageConfig createConfig(FileStorageConfig config) {
        // 租户ID由MyBatis-Plus字段自动填充器处理
        
        // 验证配置参数
        if (config.getConfigParams() != null) {
            if (!validateConfigParams(config.getConfigType(), config.getConfigParams())) {
                throw new IllegalArgumentException("配置参数验证失败");
            }
        }
        
        // 检查是否设为默认
        if (Boolean.TRUE.equals(config.getIsDefault())) {
            // 清除其他默认配置，租户ID由拦截器自动处理
            fileStorageConfigMapper.clearDefaultByTenantId();
        }
        
        this.save(config);
        log.info("创建存储配置成功: {}", config.getConfigName());
        
        return config;
    }

    @Override
    @Transactional
    public FileStorageConfig updateConfig(FileStorageConfig config) {
        FileStorageConfig existingConfig = this.getById(config.getId());
        if (existingConfig == null) {
            throw new RuntimeException("配置不存在");
        }
        
        // 验证配置参数
        if (config.getConfigParams() != null) {
            if (!validateConfigParams(config.getConfigType(), config.getConfigParams())) {
                throw new IllegalArgumentException("配置参数验证失败");
            }
        }
        
        // 检查是否设为默认
        if (Boolean.TRUE.equals(config.getIsDefault())) {
            // 清除其他默认配置，租户ID由拦截器自动处理
            fileStorageConfigMapper.clearDefaultByTenantId();
        }
        
        this.updateById(config);
        log.info("更新存储配置成功: {}", config.getConfigName());
        
        return config;
    }

    @Override
    @Transactional
    public boolean deleteConfig(String configId) {
        FileStorageConfig config = this.getById(configId);
        if (config == null) {
            return false;
        }
        
        // 检查是否为默认配置
        if (Boolean.TRUE.equals(config.getIsDefault())) {
            throw new RuntimeException("不能删除默认配置");
        }
        
        boolean result = this.removeById(configId);
        if (result) {
            log.info("删除存储配置成功: {}", config.getConfigName());
        }
        
        return result;
    }

    @Override
    @Transactional
    public int batchDeleteConfigs(List<String> configIds) {
        // 检查是否包含默认配置
        List<FileStorageConfig> configs = this.listByIds(configIds);
        boolean hasDefault = configs.stream()
                .anyMatch(config -> Boolean.TRUE.equals(config.getIsDefault()));
        
        if (hasDefault) {
            throw new RuntimeException("批量删除中包含默认配置，操作被拒绝");
        }
        
        boolean result = this.removeByIds(configIds);
        int successCount = result ? configIds.size() : 0;
        if (result) {
            log.info("批量删除存储配置成功，数量: {}", successCount);
        }
        
        return successCount;
    }

    @Override
    @Transactional
    public boolean setDefaultConfig(String configId) {
        FileStorageConfig config = this.getById(configId);
        if (config == null) {
            throw new RuntimeException("配置不存在");
        }
        
        if (!Boolean.TRUE.equals(config.getIsEnabled())) {
            throw new RuntimeException("只能设置启用的配置为默认配置");
        }
        
        // 清除当前默认配置，租户ID由拦截器自动处理
        fileStorageConfigMapper.clearDefaultByTenantId();
        
        // 设置新的默认配置，租户ID由拦截器自动处理
        int result = fileStorageConfigMapper.setAsDefault(configId);
        
        if (result > 0) {
            log.info("设置默认配置成功: {}", config.getConfigName());
            log.info("💡 配置已更新到数据库，请使用'重新加载配置'按钮或重启系统使配置生效");
        }
        
        return result > 0;
    }

    @Override
    @Transactional
    public boolean toggleConfigStatus(String configId, boolean enabled) {
        FileStorageConfig config = this.getById(configId);
        if (config == null) {
            throw new RuntimeException("配置不存在");
        }
        
        // 如果要禁用默认配置，需要先取消默认状态
        if (!enabled && Boolean.TRUE.equals(config.getIsDefault())) {
            config.setIsDefault(false);
            this.updateById(config);
        }
        
        int result = fileStorageConfigMapper.updateEnabledStatus(configId, enabled);
        
        if (result > 0) {
            log.info("切换配置状态成功: {} -> {}", config.getConfigName(), enabled ? "启用" : "禁用");
        }
        
        return result > 0;
    }

    @Override
    @Transactional
    public boolean updateSortOrder(List<FileStorageConfig> configs) {
        if (configs == null || configs.isEmpty()) {
            return false;
        }
        
        int result = fileStorageConfigMapper.batchUpdateSortOrder(configs);
        
        if (result > 0) {
            log.info("批量更新排序成功，数量: {}", configs.size());
        }
        
        return result > 0;
    }
    
    // 添加非接口方法
    @Transactional
    public boolean batchToggleStatus(List<String> configIds, boolean enabled) {
        // 如果要禁用，先检查是否包含默认配置
        if (!enabled) {
            List<FileStorageConfig> configs = this.listByIds(configIds);
            List<String> defaultConfigIds = configs.stream()
                    .filter(config -> Boolean.TRUE.equals(config.getIsDefault()))
                    .map(FileStorageConfig::getId)
                    .collect(Collectors.toList());
            
            // 先取消默认状态，租户ID由拦截器自动处理
            if (!defaultConfigIds.isEmpty()) {
                fileStorageConfigMapper.clearDefaultByTenantId();
            }
        }
        
        // 批量更新状态
        for (String configId : configIds) {
            fileStorageConfigMapper.updateEnabledStatus(configId, enabled);
        }
        
        log.info("批量切换配置状态成功，数量: {}，状态: {}", configIds.size(), enabled ? "启用" : "禁用");
        return true;
    }


    @Override
    public Map<String, Object> testConnection(FileStorageConfig config) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 这里实现具体的连接测试逻辑
            // 根据configType调用相应的存储提供者进行连接测试
            boolean success = testConnectionByType(config.getConfigType(), config.getConfigParams());
            result.put("success", success);
            result.put("message", success ? "连接测试成功" : "连接测试失败");
            result.put("timestamp", System.currentTimeMillis());
        } catch (Exception e) {
            log.warn("连接测试失败: {} - {}", config.getConfigName(), e.getMessage());
            result.put("success", false);
            result.put("message", "连接测试异常: " + e.getMessage());
            result.put("timestamp", System.currentTimeMillis());
        }
        
        return result;
    }

    @Override
    public Map<String, Object> validateConfig(String configType, String configParams) {
        Map<String, Object> result = new HashMap<>();
        
        if (!StringUtils.hasText(configParams)) {
            result.put("valid", false);
            result.put("message", "配置参数不能为空");
            return result;
        }
        
        try {
            JsonNode paramNode = objectMapper.readTree(configParams);
            boolean valid = validateConfigByType(configType, paramNode);
            result.put("valid", valid);
            result.put("message", valid ? "配置参数验证通过" : "配置参数验证失败");
        } catch (JsonProcessingException e) {
            log.warn("配置参数JSON解析失败: {}", e.getMessage());
            result.put("valid", false);
            result.put("message", "配置参数JSON格式错误: " + e.getMessage());
        }
        
        return result;
    }
    
    // 保留原方法作为内部使用
    public boolean validateConfigParams(String configType, String configParams) {
        if (!StringUtils.hasText(configParams)) {
            return false;
        }
        
        try {
            JsonNode paramNode = objectMapper.readTree(configParams);
            return validateConfigByType(configType, paramNode);
        } catch (JsonProcessingException e) {
            log.warn("配置参数JSON解析失败: {}", e.getMessage());
            return false;
        }
    }

    @Override
    public List<Map<String, Object>> getUsageStats() {
        // TODO: 实现使用统计逻辑
        List<Map<String, Object>> statsList = new ArrayList<>();
        
        // 这里应该查询每个存储配置的使用情况
        List<FileStorageConfig> configs = this.list();
        for (FileStorageConfig config : configs) {
            Map<String, Object> stats = new HashMap<>();
            stats.put("configId", config.getId());
            stats.put("configName", config.getConfigName());
            stats.put("configType", config.getConfigType());
            stats.put("fileCount", 0); // TODO: 从file表查询
            stats.put("totalSize", 0L); // TODO: 从storage_object表查询
            stats.put("lastUsedTime", null); // TODO: 查询最后使用时间
            statsList.add(stats);
        }
        
        return statsList;
    }

    @Override
    @Transactional
    public FileStorageConfig copyConfig(String sourceConfigId, String newConfigName) {
        FileStorageConfig sourceConfig = this.getById(sourceConfigId);
        if (sourceConfig == null) {
            throw new RuntimeException("源配置不存在");
        }
        
        // 创建新配置
        FileStorageConfig newConfig = new FileStorageConfig();
        newConfig.setConfigName(newConfigName);
        newConfig.setConfigType(sourceConfig.getConfigType());
        newConfig.setDescription(sourceConfig.getDescription() + " (副本)");
        newConfig.setConfigParams(sourceConfig.getConfigParams());
        newConfig.setIsEnabled(false); // 副本默认禁用
        newConfig.setIsDefault(false); // 副本不能是默认
        newConfig.setSortOrder(sourceConfig.getSortOrder());
        // 租户ID由MyBatis-Plus字段自动填充器处理
        
        this.save(newConfig);
        log.info("复制存储配置成功: {} -> {}", sourceConfig.getConfigName(), newConfigName);
        
        return newConfig;
    }

    @Override
    public List<Map<String, Object>> exportConfigs(List<String> configIds) {
        List<FileStorageConfig> configs = this.listByIds(configIds);
        List<Map<String, Object>> result = new ArrayList<>();
        
        for (FileStorageConfig config : configs) {
            Map<String, Object> configMap = new HashMap<>();
            configMap.put("configName", config.getConfigName());
            configMap.put("configType", config.getConfigType());
            configMap.put("description", config.getDescription());
            configMap.put("configParams", config.getConfigParams());
            configMap.put("sortOrder", config.getSortOrder());
            result.add(configMap);
        }
        
        return result;
    }

    @Override
    @Transactional
    public Map<String, Object> importConfigs(List<Map<String, Object>> configData) {
        Map<String, Object> result = new HashMap<>();
        int successCount = 0;
        int errorCount = 0;
        List<String> errors = new ArrayList<>();
        
        for (Map<String, Object> configMap : configData) {
            try {
                FileStorageConfig config = new FileStorageConfig();
                config.setConfigName((String) configMap.get("configName"));
                config.setConfigType((String) configMap.get("configType"));
                config.setDescription((String) configMap.get("description"));
                config.setConfigParams((String) configMap.get("configParams"));
                config.setSortOrder((Integer) configMap.getOrDefault("sortOrder", 0));
                
                // 重置关键字段
                config.setIsDefault(false); // 导入的配置不能是默认
                config.setIsEnabled(true);  // 导入的配置默认启用
                // 租户ID由MyBatis-Plus字段自动填充器处理
                
                // 检查名称唯一性
                String configName = config.getConfigName();
                if (!isConfigNameUnique(configName, null)) {
                    config.setConfigName(configName + "_导入");
                }
                
                this.save(config);
                successCount++;
            } catch (Exception e) {
                errorCount++;
                String configName = (String) configMap.getOrDefault("configName", "未知配置");
                errors.add(configName + ": " + e.getMessage());
            }
        }
        
        result.put("successCount", successCount);
        result.put("errorCount", errorCount);
        result.put("errors", errors);
        
        log.info("导入存储配置完成，成功: {}，失败: {}", successCount, errorCount);
        return result;
    }

    @Override
    public boolean isConfigNameUnique(String configName, String excludeId) {
        // 租户ID由MyBatis-Plus租户拦截器自动处理
        int count = fileStorageConfigMapper.countByNameAndTenant(configName, excludeId);
        return count == 0;
    }

    @Override
    public List<Map<String, Object>> getStorageTypeOptions() {
        List<Map<String, Object>> options = new ArrayList<>();
        
        Map<String, Object> local = new HashMap<>();
        local.put("value", "local");
        local.put("label", "本地存储");
        local.put("description", "将文件存储在本地文件系统");
        options.add(local);
        
        Map<String, Object> minio = new HashMap<>();
        minio.put("value", "minio");
        minio.put("label", "MinIO");
        minio.put("description", "分布式对象存储服务");
        options.add(minio);
        
        Map<String, Object> aliyun = new HashMap<>();
        aliyun.put("value", "aliyun");
        aliyun.put("label", "阿里云OSS");
        aliyun.put("description", "阿里云对象存储服务");
        options.add(aliyun);
        
        Map<String, Object> qcloud = new HashMap<>();
        qcloud.put("value", "qcloud");
        qcloud.put("label", "腾讯云COS");
        qcloud.put("description", "腾讯云对象存储服务");
        options.add(qcloud);
        
        return options;
    }

    @Override
    public Map<String, Object> getConfigTemplate(String configType) {
        Map<String, Object> template = new HashMap<>();
        
        switch (configType.toLowerCase()) {
            case "local":
                template.put("rootPath", "/data/files");
                template.put("createDateSubDir", true);
                template.put("baseUrl", "http://localhost:8080");
                template.put("pathPrefix", "/files");
                break;
            case "minio":
                template.put("endpoint", "http://localhost:9000");
                template.put("accessKey", "minioadmin");
                template.put("secretKey", "minioadmin");
                template.put("bucketName", "files");
                template.put("pathPrefix", "uploads");
                break;
            case "aliyun":
                template.put("endpoint", "oss-cn-hangzhou.aliyuncs.com");
                template.put("accessKey", "");
                template.put("secretKey", "");
                template.put("bucketName", "");
                template.put("pathPrefix", "uploads");
                break;
            case "qcloud":
                template.put("region", "ap-guangzhou");
                template.put("secretId", "");
                template.put("secretKey", "");
                template.put("bucketName", "");
                template.put("pathPrefix", "uploads");
                break;
            default:
                template.put("note", "未知存储类型");
        }
        
        return template;
    }

    // ==================== 私有方法 ====================
    
    /**
     * 注意：租户ID相关处理已统一由MyBatis-Plus框架处理
     * - 字段自动填充器负责在INSERT时填充tenant_id
     * - 租户拦截器负责在查询时自动添加WHERE tenant_id = ? 条件
     */
    
    /**
     * 根据配置类型验证参数
     */
    private boolean validateConfigByType(String configType, JsonNode paramNode) {
        switch (configType.toLowerCase()) {
            case "local":
                return paramNode.has("rootPath");
            case "minio":
                return paramNode.has("endpoint") && 
                       paramNode.has("accessKey") && 
                       paramNode.has("secretKey") && 
                       paramNode.has("bucketName");
            case "aliyun":
                return paramNode.has("endpoint") && 
                       paramNode.has("accessKey") && 
                       paramNode.has("secretKey") && 
                       paramNode.has("bucketName");
            case "qcloud":
                return paramNode.has("region") && 
                       paramNode.has("secretId") && 
                       paramNode.has("secretKey") && 
                       paramNode.has("bucketName");
            default:
                return false;
        }
    }
    
    /**
     * 根据配置类型测试连接
     */
    private boolean testConnectionByType(String configType, String configParams) {
        // TODO: 实现具体的连接测试逻辑
        // 这里应该根据不同的存储类型调用相应的存储提供者进行连接测试
        log.info("测试{}类型存储连接", configType);
        return true;
    }
}
